﻿using System.Text;
using System.Web;
using D.UtilCore.Dtos;
using D.UtilCore.JwtUtil;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace D.UtilCore.Filters
{
    /// <summary>
    /// Action执行前后拦截
    /// 应用场景：记录日志
    /// 使用方式：
    /// 在Action方法上面加上：[TypeFilter(typeof(ActionFilterAttribute))] 
    /// 或者：[ServiceFilter(typeof(ActionFilterAttribute))]
    /// </summary>
    public class ExtActionFilterAttribute : Attribute, IActionFilter
    {
        private readonly ILogger _logger;
        private readonly IJwtService _tokenService;
        /// <summary>
        /// 请求参数
        /// </summary>
        private string ReqParams { get; set; }
        public ExtActionFilterAttribute(ILoggerFactory loggerFactory, IJwtService tokenService)
        {
            _logger = loggerFactory.CreateLogger<ExtActionFilterAttribute>();
            _tokenService = tokenService;
        }


        /// <summary>
        /// 进入Action前
        /// </summary>
        /// <param name="context"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // 基础参数校验失败
            if (!context.ModelState.IsValid)
            {
                //var errors = new Dictionary<string, string[]>();
                var errors = new StringBuilder();
                foreach (var state in context.ModelState)
                {
                    if (state.Value.Errors.Any())
                    {
                        string[] errorMessages = state.Value.Errors.Select(x => x.ErrorMessage).ToArray();
                        //errors[state.Key] = errorMessages;
                        errors.Append(state.Key + ":" + string.Join(",", errorMessages));
                    }
                }

                ContextReturn(context, new ApiResult<int>()
                {
                    IsSuccess = false,
                    ErrorMsg = $"参数校验失败:{errors.ToString()}",
                    Code = StatusCodeEnum.Params,
                });
                return;
                //context.Result = new BadRequestObjectResult(errors);
            }

            // 控制器
            var controllerName = string.Empty;
            context.ActionDescriptor.RouteValues.TryGetValue("controller", out controllerName);

            // 方法
            var actionName = string.Empty;
            context.ActionDescriptor.RouteValues.TryGetValue("action", out actionName);

            // 记录日志
            if (context.ActionArguments.Count > 0)
            {
                ReqParams = JsonConvert.SerializeObject(context.ActionArguments);
                _logger.LogDebug($"开始执行{controllerName}控制器中{actionName}方法，参数为:{ReqParams}");
            }

            //检测是否包含'Authorization'请求头，如果不包含则直接放行
            if (actionName != "Login")
            {
                if (context.HttpContext.Request.Headers.ContainsKey("Authorization"))
                {
                    var tokenHeader = context.HttpContext.Request.Headers["Authorization"];
                    if (!string.IsNullOrEmpty(tokenHeader) && tokenHeader != "Bearer" && tokenHeader.ToString().IndexOf("Bearer") != -1)
                    {
                        // 解析Token
                        tokenHeader = tokenHeader.ToString().Substring("Bearer ".Length).Trim();
                        TokenModel tm = _tokenService.SerializeToken(tokenHeader);
                        bool hasExist = false;
                        if (tm == null)
                        {
                            hasExist = true;

                        }

                        DateTime outDateTime;
                        var appConfig = BaseApi.appConfig;
                        if (appConfig != null)
                        {
                            if (_tokenService.ValidateToken(tokenHeader, tm.Issuer, appConfig.JwtConfig.SecurityKey, out outDateTime) == null)
                            {
                                hasExist = true;
                            }
                        }
                        else
                        {
                            ContextReturn(context, new ApiResult<int>()
                            {
                                ErrorMsg = "服务器异常，请联系管理员！",
                                Code = StatusCodeEnum.Error,
                            });
                            return;
                        }

                        if (hasExist)
                        {
                            ContextReturn(context, new ApiResult<int>()
                            {
                                ErrorMsg = "登录已过期，请退出重新登录！",
                                Code = StatusCodeEnum.Waring,
                            });
                            return;
                        }
                    }
                }
            }

            // 放行
            //base.OnActionExecuting(context);
        }


        /// <summary>
        /// 返回API的信息
        /// </summary>
        /// <param name="context"></param>
        /// <param name="msg"></param>
        private void ContextReturn(ActionExecutingContext context, ApiResult<int> apiResult)
        {
            var josnStr = JsonConvert.SerializeObject(apiResult, new JsonSerializerSettings()
            {// 返回小写
                //NullValueHandling = NullValueHandling.Ignore,
                DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
            });

            context.HttpContext.Response.ContentType = "application/json;charset=utf-8";
            context.HttpContext.Response.WriteAsync(josnStr);
            context.Result = new EmptyResult();
        }

        /// <summary>
        /// 检查Ip地址是否在黑名单里面
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="request"></param>
        /// <param name="remark"></param>
        private void AccessDeny(string ip, HttpRequest request, string remark)
        {
            var path = HttpUtility.UrlDecode(request.Path + request.QueryString, Encoding.UTF8);
            //BackgroundJob.Enqueue(() => HangfireBackJob.InterceptLog(new IpIntercepter()
            //{
            //    IP = ip,
            //    RequestUrl = HttpUtility.UrlDecode(request.Scheme + "://" + request.Host + path),
            //    Time = DateTime.Now,
            //    UserAgent = request.Headers[HeaderNames.UserAgent],
            //    Remark = remark
            //}));
        }


        /// <summary>
        /// Action执行完成后
        /// </summary>
        /// <param name="context"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            var result = JsonConvert.SerializeObject(context.Result);

            //base.OnActionExecuted(context);

            TokenModel tokenModel = null;
            // 请求类型
            var method = context.HttpContext.Request.Method;

            // 请求地址
            var url = context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;

            // 控制器
            var controllerName = string.Empty;
            context.ActionDescriptor.RouteValues.TryGetValue("controller", out controllerName);

            // 方法
            var actionName = string.Empty;
            context.ActionDescriptor.RouteValues.TryGetValue("action", out actionName);

            _logger.LogDebug($"返回{controllerName}控制器中{actionName}方法，结果为:{result}");

            if (actionName != "Login")
            {// 如果不是登录

                if (context.HttpContext.Request.Headers.ContainsKey("Authorization"))
                {//检测是否包含'Authorization'请求头，如果不包含则直接放行
                    var tokenHeader = context.HttpContext.Request.Headers["Authorization"];
                    if (!string.IsNullOrEmpty(tokenHeader) && tokenHeader != "Bearer" && tokenHeader.ToString().IndexOf("Bearer") != -1)
                    {
                        // 解析Token
                        tokenHeader = tokenHeader.ToString().Substring("Bearer ".Length).Trim();
                        tokenModel = _tokenService.SerializeToken(tokenHeader);
                    }
                }
            }
        }

    }
}
